package com.varian.rabbit.util;

import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.varian.rabbit.constant.RabbitConstant;
import com.varian.rabbit.model.RabbitRoute;
import com.varian.tool.Func;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * @author ben
 * @since 2024/8/29
 */
@Slf4j
@UtilityClass
public class RabbitUtil {

    @Setter
    @Getter
    private RabbitTemplate rabbitTemplate;

    public boolean sendDelay(RabbitRoute rabbitRoute, Object message, long delay) {
        return sendDelay(rabbitRoute, message, delay, TimeUnit.MILLISECONDS);
    }

    public boolean sendDelay(String routingKey, Object message, long delay) {
        return sendDelay(routingKey, message, delay, TimeUnit.MILLISECONDS);
    }

    public boolean sendDelay(String routingKey, Object message, long delay, TimeUnit timeUnit) {
        return sendDelay(RabbitConstant.EXCHANGE_DEFAULT_TOPIC, routingKey, message, delay, timeUnit);
    }

    public boolean sendDelay(RabbitRoute rabbitRoute, Object message, long delay, TimeUnit timeUnit) {
        return sendDelay(rabbitRoute.exchange(), rabbitRoute.routingKey(), message, delay, timeUnit);
    }

    public boolean sendDelay(String exchange, String routingKey, Object message, long delay, TimeUnit timeUnit) {
        return send(exchange, routingKey, message, messageProperties -> {
            if (delay > 0) {
                messageProperties.setHeader(MessageProperties.X_DELAY, timeUnit.toMillis(delay));
            }
        });
    }

    public boolean sendExpire(String exchange, String routingKey, Object message, long expire) {
        return sendExpire(exchange, routingKey, message, expire, TimeUnit.MILLISECONDS);
    }

    public boolean sendExpire(String exchange, String routingKey, Object message, long expire, TimeUnit timeUnit) {
        return send(exchange, routingKey, message, messageProperties -> {
            if (expire > 0) {
                messageProperties.setExpiration(String.valueOf(timeUnit.toMillis(expire)));
            }
        });
    }

    public boolean sendTopic(String routingKey, Object message) {
        return send(RabbitConstant.EXCHANGE_DEFAULT_TOPIC, routingKey, message);
    }

    public boolean sendDirect(boolean condition, String routingKey, Object message) {
        if (condition) {
            return send(RabbitConstant.EXCHANGE_DEFAULT_DIRECT, routingKey, message);
        }
        return false;
    }

    public boolean sendDirect(String routingKey, Object message) {
        return send(RabbitConstant.EXCHANGE_DEFAULT_DIRECT, routingKey, message);
    }

    public boolean send(RabbitRoute rabbitRoute, Object message) {
        return send(rabbitRoute, message, Func.consumerVoid());
    }

    public boolean send(String routingKey, Object message) {
        return send(null, routingKey, message);
    }

    public boolean send(String exchange, String routingKey, Object message) {
        return send(exchange, routingKey, message, Func.consumerVoid());
    }

    public boolean send(RabbitRoute rabbitRoute, Object message, Consumer<MessageProperties> messagePropertiesConsumer) {
        return send(rabbitRoute.exchange(), rabbitRoute.routingKey(), message, messagePropertiesConsumer);
    }

    public boolean send(String exchange, String routingKey, Object message, Consumer<MessageProperties> messagePropertiesConsumer) {
        try {
            rabbitTemplate.convertAndSend(exchange, routingKey, message, processor -> {
                MessageProperties messageProperties = processor.getMessageProperties();
                messagePropertiesConsumer.accept(messageProperties);
                messageProperties.setMessageId(IdUtil.getSnowflakeNextIdStr());
                messageProperties.setContentEncoding(StandardCharsets.UTF_8.name());
                messageProperties.setAppId(SpringUtil.getApplicationName());
                messageProperties.setHeader(Func.TRACE_ID, Func.getTraceId());
                return processor;
            });
            Func.devOpt(() -> log.info("RabbitMQ发送消息成功，exchange:{}, routingKey:{}, message:{}", exchange, routingKey, Func.jackson2JsonStr(message)));
            return true;
        } catch (AmqpException e) {
            log.error("RabbitMQ发送消息失败，exchange:{}, routingKey:{}, message:{}", exchange, routingKey, Func.jackson2JsonStr(message), e);
            return false;
        }
    }
}
